﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YArchitech.Revit;
using YJKArchUtils.Utils;
using YJKRevitDimensionText.OneKeyPlanDim.LevelDim;
using YJKRevitDimensionText.OneKeyPlanDim.Utility;

namespace YJKRevitDimensionText.OneKeyPlanDim.DimData
{
	public class DbFloorDrain : DbDimBase
	{
		public DbFloorDrain(FamilyInstance floorDrain)
		{
			this.m_lstWall = KeyComponent.GetInstance().m_lstWall;
			this.m_floorDrain = floorDrain;
		}

		public override bool CreateSlopeDim(Autodesk.Revit.DB.Document doc)
		{
			XYZ point = (this.m_floorDrain.Location as LocationPoint).Point;
			Room roomAtPoint = doc.GetRoomAtPoint(point);
			if (roomAtPoint != null)
			{
				this.CreateFloorDrainTag(point, roomAtPoint, doc);
			}
			else
			{
				this.CreateFloorDrainTag(point, doc);
			}
			return true;
		}

		private void CreateFloorDrainTag(XYZ ptLocation, Autodesk.Revit.DB.Document doc)
		{
			double num = double.MaxValue;
			List<XYZ> list = new List<XYZ>();
			foreach (Wall wall in this.m_lstWall)
			{
				Curve curve = (wall.Location as LocationCurve).Curve;
				if (!(curve == null))
				{
					this.m_lstWallLocationCv.Add(curve);
					Curve curve2 = curve.Clone();
					curve2.MakeUnbound();
					XYZ xyzpoint = curve2.Project(ptLocation).XYZPoint;
					if (xyzpoint != null)
					{
						list.Add(xyzpoint);
						double num2 = ptLocation.DistanceTo(xyzpoint);
						if (Geometry.LessThan(num2, num))
						{
							num = num2;
						}
					}
				}
			}
			this.CreateDim(ptLocation, num, list, doc);
		}

		private void CreateFloorDrainTag(XYZ ptLocation, Room room, Autodesk.Revit.DB.Document doc)
		{
			double dMin = double.MaxValue;
			List<XYZ> list = new List<XYZ>();
			foreach (List<Curve> list2 in DbFloorDrain.GetRoomOutBoundary(room, 0))
			{
				for (int i = 0; i < list2.Count; i++)
				{
					for (int j = i + 1; j < list2.Count; j++)
					{
						XYZ xyz = null;
						dMin = DbFloorDrain.GetMinDistance(ptLocation, dMin, list2[i], list2[j], ref xyz);
						if (xyz != null)
						{
							list.Add(xyz);
						}
					}
				}
				XYZ xyz2 = null;
				dMin = DbFloorDrain.GetMinDistance(ptLocation, dMin, list2[0], list2[list2.Count - 1], ref xyz2);
				if (xyz2 != null)
				{
					list.Add(xyz2);
				}
			}
			this.CreateDim(ptLocation, dMin, list, doc);
		}

		private void CreateDim(XYZ ptLocation, double dMin, List<XYZ> lstPtLocations, Autodesk.Revit.DB.Document doc)
		{
			AssistFunc.CompressArray(lstPtLocations);
			List<XYZ> list = new List<XYZ>();
			foreach (XYZ xyz in lstPtLocations)
			{
				if (Geometry.IsEqual(ptLocation.DistanceTo(xyz), dMin, 0.1))
				{
					list.Add(xyz);
				}
			}
			double num = (double)doc.ActiveView.Scale;
			SlopeDimData slopeDimData = new SlopeDimData(doc);
			foreach (XYZ xyz2 in list)
			{
				XYZ xyz3 = new XYZ(ptLocation.X, ptLocation.Y, 0.0);
				XYZ xyz4 = (new XYZ(xyz2.X, xyz2.Y, 0.0) - xyz3).Normalize();
				XYZ xyz5 = ptLocation - xyz4 * AssistFunc.mmToFeet(500.0);
				slopeDimData.SlopeDimDir = xyz4;
				slopeDimData.PtStart = xyz5;
				slopeDimData.DimVal = "0.5%";
				FamilyInstance familyInstance = slopeDimData.CreateSlopeDim();
				if (familyInstance != null)
				{
					Parameter parameter = RevitElementExtension.GetParameter(familyInstance, "箭头长度");
					if (parameter != null)
					{
						double num2 = parameter.AsDouble() * num;
						parameter = RevitElementExtension.GetParameter(familyInstance, "基线长度");
						if (parameter != null)
						{
							double num3 = parameter.AsDouble() * num;
							XYZ ptEnd = xyz5 - (num2 + num3) * xyz4;
							this.m_SlopeDimLength = num2 + num3;
							CommonInterface.MoveElement(familyInstance, xyz5, ptEnd, doc);
							this.SetDimPosition(familyInstance);
						}
					}
				}
			}
		}

		public void SetDimPosition(FamilyInstance familyDim)
		{
			CurveLoop slopeDimCurveLoop = OcclusionArea.GetSlopeDimCurveLoop(familyDim);
			LocationPoint locationPoint = familyDim.Location as LocationPoint;
			if (locationPoint == null)
			{
				return;
			}
			XYZ point = locationPoint.Point;
			List<CurveLoop> list = new List<CurveLoop>();
			list.AddRange(OcclusionArea.GetInstance().m_lstColumnCvLoop);
			list.AddRange(OcclusionArea.GetInstance().m_lstOpeningCvLoop);
			list.AddRange(OcclusionArea.GetInstance().m_lstSizeDimCvLoop);
			list.AddRange(OcclusionArea.GetInstance().m_lstSlopeDimCvLoop);
			list.AddRange(OcclusionArea.GetInstance().m_lstLevelDimCvLoop);
			Line line = this.LineFromSlopeDimToDrain(point);
			int num = 12;
			int i = 0;
			while (i < num + 1)
			{
				double num2 = (double)i * Math.PI*2 / (double)num;
				Transform transform = RevitVersionFuncs.CreateRotationAtPoint(XYZ.BasisZ, num2, (this.m_floorDrain.Location as LocationPoint).Point);
				Line line2 = line.CreateTransformed(transform) as Line;
				new List<Curve>().Add(line2);
				if (!CommonInterface.IsExistOcclusion(CurveLoop.CreateViaTransform(slopeDimCurveLoop, transform), list) && !this.bHasIntersectWithWall(this.m_lstWallLocationCv, line2))
				{
					familyDim = (CommonInterface.RotateElement(familyDim, (this.m_floorDrain.Location as LocationPoint).Point, XYZ.BasisZ, num2) as FamilyInstance);
					if (familyDim == null)
					{
						return;
					}
					KeyComponent.GetInstance().m_lstSlopeDimension.Add(familyDim);
					break;
				}
				else
				{
					i++;
				}
			}
			OcclusionArea.GetInstance().m_lstSlopeDimCvLoop.Add(slopeDimCurveLoop);
		}

		private bool bHasIntersectWithWall(List<Curve> lstCv, Line line)
		{
			IntersectionResultArray intersectionResultArray = null;
			foreach (Curve curve in lstCv)
			{
				curve.Intersect(line, out intersectionResultArray);
				if (intersectionResultArray != null)
				{
					XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
					if (xyzpoint != null)
					{
						return true;
					}
				}
			}
			return false;
		}

		private Line LineFromSlopeDimToDrain(XYZ pt)
		{
			pt = new XYZ(pt.X, pt.Y, 0.0);
			Line result = null;
			try
			{
				XYZ xyz = (this.m_floorDrain.Location as LocationPoint).Point;
				xyz = new XYZ(xyz.X, xyz.Y, 0.0);
				pt += (pt - xyz).Normalize() * this.m_SlopeDimLength;
				result = Line.CreateBound(pt, xyz);
			}
			catch
			{
			}
			return result;
		}

		private static double GetMinDistance(XYZ ptLocation, double dMin, Curve cv1, Curve cv2, ref XYZ ptIntersect)
		{
			IntersectionResultArray intersectionResultArray = null;
			cv1.Intersect(cv2, out intersectionResultArray);
			if (intersectionResultArray != null)
			{
				ptIntersect = intersectionResultArray.get_Item(0).XYZPoint;
				double num = ptLocation.DistanceTo(ptIntersect);
				if (Geometry.LessThan(num, dMin))
				{
					dMin = num;
				}
			}
			return dMin;
		}

		public static List<List<Curve>> GetRoomOutBoundary(Room room, SpatialElementBoundaryLocation lcType = 0)
		{
			List<List<Curve>> list = new List<List<Curve>>();
			foreach (IList<BoundarySegment> list2 in room.GetBoundarySegments(new SpatialElementBoundaryOptions
			{
				SpatialElementBoundaryLocation = lcType
			}))
			{
				if (list2 != null && list2.Count > 0)
				{
					List<Curve> list3 = new List<Curve>();
					foreach (BoundarySegment boundarySegment in list2)
					{
						if (boundarySegment != null)
						{
							list3.Add(UnifiedModified.GetBoundarySegmentCurve(boundarySegment));
						}
					}
					list.Add(list3);
				}
			}
			return list;
		}

		private FamilyInstance m_floorDrain;

		private List<Wall> m_lstWall = new List<Wall>();

		private List<Curve> m_lstWallLocationCv = new List<Curve>();

		private XYZ m_SlopePtInsert = XYZ.Zero;

		private XYZ m_SlopeDir = XYZ.Zero;

		private double m_SlopeDimLength;
	}
}
